<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>视频筛选器(双层多分类版)</title>
    <style>
        body { text-align: center; font-family: Arial; }
        video {
            width: 1280px;
            height: 720px;
            margin-top: 20px;
            background-color: #000;
        }
        button { margin: 10px; padding: 10px 20px; font-size: 16px; }
        select { margin: 0 6px; padding: 6px; font-size: 14px; }
        #progress { margin: 10px; font-size: 18px; }
        .video-item {
            display: inline-block;
            margin: 5px;
            padding: 5px 8px;
            border: 1px solid #ccc;
            border-radius: 5px;
            font-size: 13px;
        }
        .video-status-0 { background-color: #fff; }
        .video-status-1 { background-color: #c8e6c9; }
        .video-status--1 { background-color: #ffcdd2; }
        .current-video { border: 3px solid #2196F3; }
        #statistics { margin: 15px 0; font-size: 16px; font-weight: bold; }
        .stat-item {
            display: inline-block; margin: 0 10px; padding: 5px 10px; border-radius: 5px;
        }
        .satisfied { background-color: #c8e6c9; }
        .unsatisfied { background-color: #ffcdd2; }
        .unmarked { background-color: #fff; border: 1px solid #ccc; }
        #categoryPanel { margin-top: 10px; }
        #categoryHint { color: #e91e63; font-size: 12px; display: none; }
        #currentChoice { font-size: 13px; color: #555; margin-left: 8px; }
        #timeSegmentPanel input[type="time"] {
        width: 140px;
        height: 38px;
        font-size: 20px;
        margin-right: 8px;
        }
        #segmentContent {
            width: 240px;
            height: 38px;
            font-size: 20px;
            margin-right: 8px;
        }
        #timeSegmentPanel button {
            padding: 6px 14px;
            font-size: 14px;
    }
    </style>
</head>
<body>
    <h1>视频筛选器(双层多分类版)</h1>
    <h6 style="color: red">【按Enter键快速标记，按←键或者→键切换上一个或下一个视频，切勿按Delete键！】</h6>
    <div id="progress">进度: <span id="current">1</span> / <span id="total">1</span></div>

    <div id="statistics">
        <span class="stat-item satisfied">满足: <span id="satisfiedCount">0</span></span>
        <span class="stat-item unsatisfied">不满足（请忽略）: <span id="unsatisfiedCount">0</span></span>
        <span class="stat-item unmarked">未标记: <span id="unmarkedCount">0</span></span>
    </div>

    <video id="videoPlayer" controls></video>



    <!-- 多分类（两级级联） -->
    <div id="categoryPanel">
        <span>分类选择（两级级联）:</span>
        <select id="superCategory">
            <option value="">请选择大类</option>
        </select>
        <select id="subCategory" disabled>
            <option value="">请选择子类</option>
        </select>
        <span id="currentChoice"></span>
        <div id="categoryHint">未检测到规范的分类定义，请将符合规范的 JSON 放入`json`目录。</div>
    </div>

    <!-- 添加时间段标注区域 -->
    <div id="timeSegmentPanel" style="margin-top: 15px;">
        <span>片段标记（startTime、endTime、content） :</span>
        <label>起始时间: <input type="time" id="startTime" step="1" value="00:00:00"></label>
        <label>终止时间: <input type="time" id="endTime" step="1" value="00:00:00"></label>
        <label>标记内容: <input type="text" id="segmentContent" value="出现了内容" style="width: 180px;"></label>
        <button onclick="jumpToStartTime()" style="background-color: #607D8B; color: white;font-size: 18px;" >跳转预览</button>
    </div>

     <div>
        <button onclick="switchVideo(-1)">上一个</button>
        <button onclick="switchVideo(1)">下一个</button>
    </div>

<!--    <button id="markBtn" onclick="markCurrentVideo()" style="background-color: #4CAF50; color: white;">标记视频 (回车)</button>-->
    <button id="markBtn" onclick="markCurrentVideo()" style="background-color: #4CAF50; color: white; padding: 15px 30px; font-size: 18px;">标记视频 (回车)</button>
<!--    <button onclick="rejectCurrentVideo()" style="background-color: #f44336; color: white;">拒绝视频 (Delete)</button>-->
    <br>
    <button onclick="refreshProgress()" style="background-color: #2196F3; color: white;">刷新进度</button>
    <button onclick="forceUpdateProgress()" style="background-color: #FF9800; color: white;">强制更新进度</button>
    <button onclick="updateDatabase()" style="background-color: #9C27B0; color: white;">更新数据库</button>
    <button onclick="exportExcel()" style="background-color: #009688; color: white;">导出Excel</button>

    <div id="videoList"></div>

    <script>
        let videos = [];
        let categories = [];
        let currentIndex = 0;

        const player = document.getElementById("videoPlayer");
        const currentSpan = document.getElementById("current");
        const totalSpan = document.getElementById("total");
        const videoListDiv = document.getElementById("videoList");
        const satisfiedCountSpan = document.getElementById("satisfiedCount");
        const unsatisfiedCountSpan = document.getElementById("unsatisfiedCount");
        const unmarkedCountSpan = document.getElementById("unmarkedCount");

        const superSelect = document.getElementById("superCategory");
        const subSelect = document.getElementById("subCategory");
        const markBtn = document.getElementById("markBtn");
        const categoryHint = document.getElementById("categoryHint");
        const currentChoice = document.getElementById("currentChoice");

        // 初始化：先加载分类，再加载视频
        (async function init() {
            await loadCategories();
            await loadVideos();
            bindCategoryEvents();
        })();

        async function loadCategories() {
            try {
                const res = await fetch("/api/categories");
                const data = await res.json();
                categories = Array.isArray(data.categories) ? data.categories : [];

                populateSuperOptions(categories);
                updateCategoryUIState();
            } catch (e) {
                categories = [];
                populateSuperOptions(categories);
                updateCategoryUIState();
            }
        }

        function populateSuperOptions(cats) {
            superSelect.innerHTML = '<option value="">请选择大类</option>';
            if (!Array.isArray(cats)) return;
            for (const root of cats) {
                const opt = document.createElement("option");
                opt.value = root.value;
                opt.textContent = root.label;
                superSelect.appendChild(opt);
            }
            // 子类初始禁用
            subSelect.innerHTML = '<option value="">请选择子类</option>';
            subSelect.disabled = true;
            currentChoice.textContent = '';
        }

        function populateSubOptions(superVal) {
            subSelect.innerHTML = '<option value="">请选择子类</option>';
            const root = categories.find(c => c.value === superVal);
            if (root && Array.isArray(root.children) && root.children.length > 0) {
                for (const child of root.children) {
                    const opt = document.createElement("option");
                    opt.value = child.value;
                    opt.textContent = child.label;
                    subSelect.appendChild(opt);
                }
                subSelect.disabled = false;
            } else {
                subSelect.disabled = true;
            }
        }

        function updateCategoryUIState() {
            const hasCats = Array.isArray(categories) && categories.length > 0;
            categoryHint.style.display = hasCats ? "none" : "block";
            superSelect.disabled = !hasCats;
            subSelect.disabled = !hasCats || !superSelect.value;
            markBtn.disabled = !hasCats;
        }

        function bindCategoryEvents() {
            superSelect.addEventListener("change", () => {
                populateSubOptions(superSelect.value);
                updateCurrentChoice();
            });
            subSelect.addEventListener("change", updateCurrentChoice);
        }

        function updateCurrentChoice() {
            const sc = superSelect.value || '';
            const sLabel = sc ? (categories.find(c => c.value === sc)?.label || sc) : '';
            const sub = subSelect.value || '';
            const subLabel = sub ? ((categories.find(c => c.value === sc)?.children || []).find(ch => ch.value === sub)?.label || sub) : '';
            currentChoice.textContent = sc && sub ? `当前选择: ${sLabel} / ${subLabel}` : '';
        }

        async function loadVideos() {
            const res = await fetch("/api/videos");
            const data = await res.json();
            videos = data.videos || [];

            updateStatistics(data.statistics);
            if (videos.length > 0) {
                totalSpan.textContent = videos.length;

                // 找到第一个未处理的视频
                let firstUnprocessedIndex = 0;
                for (let i = 0; i < videos.length; i++) {
                    if (videos[i].status === 0) { firstUnprocessedIndex = i; break; }
                }
                currentIndex = firstUnprocessedIndex;
                loadVideo(currentIndex);
                updateProgress();
                renderVideoList();
            }
            console.log("Loaded videos:", videos);
        }

        function loadVideo(index) {
            if (index < 0 || index >= videos.length) return;
            const v = videos[index];

            player.src = `/videos/${v.filename}`;
            player.load();

            // 回填当前视频的分类选择
            setSelectionForVideo(v);

            // 保存当前索引到localStorage作为备份
            localStorage.setItem('videoIndex', index.toString());

            renderVideoList();
        }

        function setSelectionForVideo(video) {
    // 分类相关逻辑
    superSelect.value = "";
    populateSubOptions("");
    subSelect.value = "";
    updateCurrentChoice();

    const sc = video.super_category || "";
    const sub = video.sub_category || "";
    if (!sc || !sub) {
        updateCategoryUIState();
    } else {
        const root = categories.find(c => c.value === sc);
        if (root) {
            superSelect.value = sc;
            populateSubOptions(sc);
            const leafOk = (root.children || []).some(ch => ch.value === sub);
            if (leafOk) {
                subSelect.value = sub;
            }
        }
        updateCurrentChoice();
        updateCategoryUIState();
    }

    // 片段标记相关逻辑（无内容时重置为默认值）
    document.getElementById("startTime").value = video.start_time || "00:00:00";
    document.getElementById("endTime").value = video.end_time || "00:00:00";
    document.getElementById("segmentContent").value = video.segment_content || "标记了内容（默认）";

    updateCategoryUIState();
}

        function updateProgress() {
            currentSpan.textContent = currentIndex + 1;
            totalSpan.textContent = videos.length;
        }

        function updateStatistics(statistics) {
            if (statistics) {
                satisfiedCountSpan.textContent = statistics.satisfied;
                unsatisfiedCountSpan.textContent = statistics.unsatisfied;
                unmarkedCountSpan.textContent = statistics.unmarked;
            }
        }

        function renderVideoList() {
            videoListDiv.innerHTML = '';
            videos.forEach((video, index) => {
                const videoElement = document.createElement('div');
                videoElement.className = `video-item video-status-${video.status} ${index === currentIndex ? 'current-video' : ''}`;
                const catText = (video.super_category && video.sub_category) ? ` [${video.super_category}/${video.sub_category}]` : '';
                videoElement.textContent = `${index + 1}. ${video.filename} (${getStatusText(video.status)})${catText}`;

                videoElement.onclick = () => {
                    currentIndex = index;
                    loadVideo(currentIndex);
                    updateProgress();
                };
                videoListDiv.appendChild(videoElement);
            });
        }

        function getStatusText(status) {
            switch(status) {
                case 1: return '已标记';
                case -1: return '已拒绝';
                default: return '未处理';
            }
        }

        function switchVideo(direction) {
            currentIndex += direction;
            if (currentIndex < 0) currentIndex = 0;
            if (currentIndex >= videos.length) currentIndex = videos.length - 1;
            loadVideo(currentIndex);
            updateProgress();
        }

        function getSelectedCategory() {
            const super_category = superSelect.value;
            const sub_category = subSelect.value;
            if (!super_category || !sub_category) return null;
            return { super_category, sub_category };
        }

        function timeStrToSeconds(str) {
            const [h, m, s] = str.split(":").map(Number);
            return h * 3600 + m * 60 + s;
        }

    async function markCurrentVideo() {
            if (!Array.isArray(categories) || categories.length === 0) {
                alert("未检测到规范分类，无法标记。");
                return;
            }
            const currentVideo = videos[currentIndex];
            const selected = getSelectedCategory();
            if (!selected) {
                alert("请选择大类与子类后再标记。");
                return;
            }
            const startTime = document.getElementById("startTime").value;
            const endTime = document.getElementById("endTime").value;
            const segmentContent = document.getElementById("segmentContent").value.trim();

            // 时间校验
            if (!startTime || !endTime || !segmentContent) {
                alert("请填写起始时间、终止时间和片段内容后再标记。");
                return;
            }
            if (startTime === "00:00:00" && endTime === "00:00:00") {
                alert("起始时间和终止时间不能都为 00:00:00，请填写有效时间段。");
                return;
            }
            if (timeStrToSeconds(startTime) > timeStrToSeconds(endTime)) {
                alert("起始时间不能大于终止时间，请检查时间段。");
                return;
            }
            // 获取视频总时长（秒）
            const videoDuration = player.duration;

            // 校验时间是否超出视频总时长
            if (timeStrToSeconds(startTime) > videoDuration || timeStrToSeconds(endTime) > videoDuration) {
                alert("起始时间或终止时间超出了视频总时长，请检查输入。");
                return;
            }
            const payload = {
                filename: currentVideo.filename,
                super_category: selected.super_category,
                sub_category: selected.sub_category,
                index: currentIndex,
                start_time: startTime,
                end_time: endTime,
                segment_content: segmentContent
            };
            const res = await fetch("/api/mark", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(payload)
            });

            if (!res.ok) {
                const err = await res.json().catch(()=>({detail:"标记失败"}));
                alert(err.detail || "标记失败");
                return;
            }

            const data = await res.json();
            videos[currentIndex].status = 1;
            videos[currentIndex].super_category = selected.super_category;
            videos[currentIndex].sub_category = selected.sub_category;
            videos[currentIndex].start_time = startTime;
            videos[currentIndex].end_time = endTime;
            videos[currentIndex].segment_content = segmentContent;
            currentIndex = data.next_index;
            loadVideo(currentIndex);
            updateProgress();
            updateStatistics(data.statistics);
        }



        async function rejectCurrentVideo() {
            const currentVideo = videos[currentIndex];
            const res = await fetch("/api/reject", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ filename: currentVideo.filename, index: currentIndex })
            });

            if (!res.ok) {
                const err = await res.json().catch(()=>({detail:"拒绝失败"}));
                alert(err.detail || "拒绝失败");
                return;
            }

            const data = await res.json();
            videos[currentIndex].status = -1;
            currentIndex = data.next_index;
            loadVideo(currentIndex);
            updateProgress();
            updateStatistics(data.statistics);
        }

        async function refreshProgress() {
            await fetch("/api/force-update-progress", { method: "POST" });
            const res = await fetch("/api/videos");
            const data = await res.json();
            videos = data.videos;
            updateStatistics(data.statistics);

            if (videos.length > 0) {
                totalSpan.textContent = videos.length;
                let firstUnprocessedIndex = 0;
                for (let i = 0; i < videos.length; i++) {
                    if (videos[i].status === 0) { firstUnprocessedIndex = i; break; }
                }
                currentIndex = firstUnprocessedIndex;
                loadVideo(currentIndex);
                updateProgress();
                renderVideoList();
                alert("进度已刷新，已跳转到第一个未处理的视频");
            }
        }

        async function forceUpdateProgress() {
            const res = await fetch("/api/force-update-progress", { method: "POST" });
            const data = await res.json();
            updateStatistics(data.statistics);
            location.reload();
        }

        async function updateDatabase() {
            const res = await fetch("/api/update-database", { method: "POST" });
            const data = await res.json();
            updateStatistics(data.statistics);
            alert("数据库已更新");
            location.reload();
        }

        async function exportExcel() {
            // 直接请求导出接口，后端未标完会返回 400
            const res = await fetch("/api/export");
            if (!res.ok) {
                const err = await res.json().catch(()=>({detail:"导出失败"}));
                alert(err.detail || "导出失败");
                return;
            }
            const blob = await res.blob();
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = "videos.xlsx";
            document.body.appendChild(a);
            a.click();
            a.remove();
            window.URL.revokeObjectURL(url);
        }

        function jumpToStartTime() {
            const startTimeStr = document.getElementById("startTime").value;
            const [h, m, s] = startTimeStr.split(":").map(Number);
            const seconds = h * 3600 + m * 60 + s;
            player.currentTime = seconds;
            player.play();
        }


        document.addEventListener("keydown", function(e) {
            if (e.key === "ArrowLeft") switchVideo(-1);
            else if (e.key === "ArrowRight") switchVideo(1);
            else if (e.key === "Enter") { markCurrentVideo(); }
            else if (e.key === "Delete") { rejectCurrentVideo(); }
        });
    </script>
</body>
</html>